#include "basicparser2.h"
#include "errors.h"

namespace CCompiler
{
    std::map<std::string, TinyNameType> strToTNT;

    SynExpression * BasicParser2::parseFunction(SynExpression *expr)
    {
        SynFunctionCall *func = new SynFunctionCall(expr);
        if(getTokenType() != ttCloseParenthesis)
            func->pushArgument(parseExpression());
        while(getTokenType() == ttComma)
        {
            nextToken();
            func->pushArgument(parseExpression());
        }
        if(getTokenType() != ttCloseParenthesis)
            throw Errors::SyntaxError("Parenthesis mismatch", tok_);
        nextToken();
        return func;
    }

    SynExpression * BasicParser2::parseArray(SynExpression *expr)
    {
        SynBinaryOp *res = new SynBinaryOp("[]", expr, parseExpression());
        if(getTokenType() != ttCloseBracket)
            throw Errors::SyntaxError("Square brackets mismatch", tok_);
        nextToken();
        return res;
    }

    SynExpression * BasicParser2::parseStruct(SynExpression *expr)
    {
        if(getTokenType() != ttIdentifier) throw Errors::SyntaxError("Expected identifier", tok_);
        SynDot *dot = new SynDot(expr, new SynVal(tok_.getText()));
        nextToken();
        return dot;
    }

    SynExpression * BasicParser2::parseOtherOps(SynExpression *expr, TinyNameType nt, bool skipCheck /*= false*/ )
    {
        for(;;)
        {
            switch (getTokenType())
            {
            case ttOpenParenthesis:
                {
                    if(!(skipCheck || nt == ntFunction))
                        throw Errors::SyntaxError(((SynVal *)expr)->getName() + " isn't a function", tok_);
                    nextToken();
                    expr = parseFunction(expr);
                    break;
                }
            case ttOpenBracket:
                {
                    if(!(skipCheck || nt == ntArray))
                        throw Errors::SyntaxError(((SynVal *)expr)->getName() + " isn't an array", tok_);
                    nextToken();
                    expr = parseArray(expr);
                    break;
                }
            case ttDot:
                {
                    if(!(skipCheck || nt == ntStruct))
                        throw Errors::SyntaxError(((SynVal *)expr)->getName() + " isn't a struct", tok_);
                    nextToken();
                    expr = parseStruct(expr);
                    break;
                }
            default:
                return expr;
            }
            skipCheck = true;
        }
    }

    SynExpression *BasicParser2::parseIdentifier()
    {
        if(getTokenType() != ttIdentifier)
            throw Errors::SyntaxError("Expected identifier", tok_);
        if(!tinySymbolTable.count(tok_.getText()))
            throw Errors::SyntaxError("Name " + tok_.getText() + " wasn't declared", tok_);
        SynVal *identifier = new SynVal(tok_.getText());
        nextToken();
        TinyNameType vartype = tinySymbolTable[identifier->getName()];
        return parseOtherOps(identifier, vartype);
    }

    SynExpression *BasicParser2::parseExpression2()
    {
        if(strToTNT.count(tok_.getText()))
        {
            std::string tname = tok_.getText();
            nextToken();
            if(getTokenType() == ttIdentifier)
                tinySymbolTable[tok_.getText()] = strToTNT[tname];
            else
                throw Errors::SyntaxError("Expected declaring name", tok_);
            nextToken();
        }
        else if(getTokenType() != ttEof)
            return parseExpression();
        else
            throw Errors::EndOfFile();
        return parseExpression2();
    }

}

namespace __InitializeBasicParser2
{
    using namespace CCompiler;

    void initialize()
    {
        strToTNT["int"] = ntVariable;
        strToTNT["double"] = ntVariable;
        strToTNT["void"] = ntFunction;
        strToTNT["struct"] = ntStruct;
        strToTNT["typedef"] = ntArray;
    }
}
